﻿using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using WorkFlowCore.Authorization;
using WorkFlowCore.Conditions;
using WorkFlowCore.IRepositories;
using WorkFlowCore.UserSelectors;
using WorkFlowCore.Workflows;

namespace WorkFlowCore.WorkTasks
{
    public class StepForecastManager:IDomainService
    {
        private readonly ConditionManager conditionManager;
        private readonly UserSelectorManager userSelectorManager;
        private readonly WorkflowStore _workflowStore;
        private readonly IWorkTaskRepository _workTaskRepository;
        private readonly IWorkflowSession _workflowSession;
        private readonly IWorkStepRepository _workStepRepository;
        public StepForecastManager(WorkflowStore workflowStore, IWorkTaskRepository workTaskRepository, ConditionManager conditionManager, UserSelectorManager userSelectorManager, IWorkflowSession workflowSession, IWorkStepRepository workStepRepository)
        {
            _workflowStore = workflowStore;
            _workTaskRepository = workTaskRepository;
            this.conditionManager = conditionManager;
            this.userSelectorManager = userSelectorManager;
            _workflowSession = workflowSession;
            _workStepRepository = workStepRepository;
        }

        public async Task<List<ForecastNodeUser>> GetForecastNodeUsers(Guid taskId)
        {
            //TODO 结合已经审批的 step 获取已经审批节点的用户，同时对于审批中的用户解析需要结合 step 的表单
            //生成一个方法，获取task，再获取workflow，再获取当前节点，再获取下一节点，再获取下一节点的用户
            var workTask = (await _workTaskRepository.GetAsync(taskId))?.ToWorkTask();
            if (workTask == null)
            {
                return null;
            }
            var workflow = await _workflowStore.GetWorkflowVersion(workTask.WorkflowId.Id, workTask.WorkflowId.VersionNo);

            var startNode = (workflow.NodeMaps ?? new List<NodeMap>()).FirstOrDefault(n => n.FromNode.NodeType == WorkNodeType.Begin)?.FromNode;
            var steps = await GetPenddingOrRunningSteps(taskId);

            //获取已处理的步骤,从起始节点一层一层的往下取，获取对应节点的step，如果有并且是已处理，则构造 ForecastNodeUser，
            //否则，根据处理中的step结合用户选择器去获取用户，构造 ForecastNodeUser

            var forecastNodeUsers = await GetForecastNodeUsers(workflow, workTask, 1, steps, null, startNode);

            return forecastNodeUsers;
        }

        public async Task<List<ForecastNodeUser>> GetForecastNodeUsers(WorkflowId workflowId, string formData)
        {
            //TODO 结合已经审批的 step 获取已经审批节点的用户，同时对于审批中的用户解析需要结合 step 的表单
            if (workflowId == null)
            {
                return null;
            }
            var workflow = await _workflowStore.GetWorkflowVersion(workflowId.Id, workflowId.VersionNo);

            var startNode = (workflow.NodeMaps??new List<NodeMap>()).FirstOrDefault(n => n.FromNode.NodeType == WorkNodeType.Begin)?.FromNode;

            var forecastNodeUsers = await GetForecastNodeUsers(workflow, new WorkTask(workflowId,formData, _workflowSession?.User?.Id), 1,null,null, startNode);

            return forecastNodeUsers;
        }



        private async Task<List<ForecastNodeUser>> GetForecastNodeUsers(WorkflowVersion workflowVersion, WorkTask workTask, int level,List<WorkStep> steps, ForecastNodeUser latestNode, params WorkflowNode[] nodes)
        {
            var forecastNodeUsers = new List<ForecastNodeUser>();
            if (nodes == null || nodes.Length == 0)
            {
                return forecastNodeUsers;
            }
            nodes = nodes.Where(n => n != null).ToArray();
            

            foreach (var node in nodes)
            {
                var forecastNodeUser = new ForecastNodeUser();
                forecastNodeUsers.Add(forecastNodeUser);
                forecastNodeUser.NodeId = node.Id;
                forecastNodeUser.NodeName = node.Name;
                forecastNodeUser.Level = level;
                forecastNodeUser.Users = new List<ForecastUser>();

                

                var nodeSteps = (steps ?? new List<WorkStep>()).Where(s => s.NodeId == node.Id).ToList();
                if ((workTask?.WorkTaskStatus == WorkTaskStatus.Processing || workTask?.WorkTaskStatus == WorkTaskStatus.Processed) && latestNode == null && nodeSteps != null && nodeSteps.Count > 0)
                {

                    var latestGroupId = nodeSteps.OrderByDescending(n => n.CreationTime).FirstOrDefault().GroupId;

                    nodeSteps = nodeSteps.Where(n=>n.GroupId==latestGroupId).ToList();  

                    foreach (var nodeStep in nodeSteps)
                    {
                        forecastNodeUser.Users.Add(new ForecastUser(nodeStep.HandleUser, nodeStep.HandleType, nodeStep.WorkStepType));
                    }
                }
                else
                {
                    var nodeUsers = node.GetHandleUsers(workTask, userSelectorManager);

                    foreach (var nodeUser in nodeUsers)
                    {
                        forecastNodeUser.Users.AddRange(nodeUser.Value.Select(user=>new ForecastUser(user,null, (WorkStepType)nodeUser.Key)));
                    }
                    forecastNodeUser.Users = forecastNodeUser.Users.Distinct().ToList();
                }
                forecastNodeUser.Users = forecastNodeUser.Users.Where(u => u.Id != null && !string.IsNullOrWhiteSpace(u.Name)).ToList();
            }


            var toNodes = new List<WorkflowNode>();

            foreach (var node in nodes)
            {
                var nextNodes = await GetNextNodes(workflowVersion, node, workTask, new WorkStep());
                foreach (var nextNode in nextNodes)
                {
                    if(!toNodes.Any(tn=>tn.Id==nextNode.Id))
                    {
                        toNodes.Add(nextNode);
                    }
                }
            }
            if(latestNode == null)
            {
                var latestStep = (steps ?? new List<WorkStep>()).Where(s=>s.IsHandled==false).OrderByDescending(s => s.CreationTime).FirstOrDefault();
                latestNode = forecastNodeUsers.FirstOrDefault(n => n.NodeId == latestStep?.NodeId);
            }
            
            forecastNodeUsers.AddRange(await GetForecastNodeUsers(workflowVersion, workTask, level + 1,steps, latestNode, toNodes.ToArray()));

            return forecastNodeUsers;
        }



        /// <summary>
        /// 获取审批的下一步节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="workTask"></param>
        /// <returns></returns>
        private async Task<List<WorkflowNode>> GetNextNodes(WorkflowVersion workflowVersion, WorkflowNode node, WorkTask workTask, WorkStep cuttentWorkStep)
        {
            var nodes = new List<WorkflowNode>();

            //var workflowVersion = await workflowStore.GetWorkflowVersion(workTask.WorkflowId.Id, workTask.WorkflowId.VersionNo);
            //普通节点的下组节点要排除掉 子流程节点
            var toNodeLines = workflowVersion.NodeMaps.Where(n => n.FromNode.Id == node.Id && n.MapType == NodeMap.NodeMapType.Normal && n.ToNode.NodeType != WorkNodeType.SubNode);

            foreach (var line in toNodeLines)
            {
                if (line.CanAccept(workTask, cuttentWorkStep, conditionManager))
                {
                    var tonode = line.ToNode;
                    nodes.Add(tonode);
                }
            }
            return nodes;
        }

        private async Task<List<WorkStep>> GetPenddingOrRunningSteps(Guid workTaskId)
        {
            //获取待处理或者已经处理了的步骤列表 
            var workSteps = (await _workStepRepository.GetListAsync(w => w.WorkTaskId == workTaskId )).Select(s => s.ToWorkStep()).ToList();
            
            
            //var returnSteps = new List<WorkStep>();
            ////获取已处理的步骤
            //var passList = workSteps.Where(s=>!(s.IsHandled && s.HandleType == WorkStepHandleType.UnWork))
            //    .GroupBy(ws=>ws.NodeId)
            //    .Select(g=>g.OrderByDescending(s=>s.CreationTime).FirstOrDefault())
            //    .Where(w=>(w.IsHandled && w.HandleType == WorkStepHandleType.Pass)).ToList();
            //returnSteps.AddRange(passList);
            ////获取处理中的步骤
            //var processingList = workSteps.Where(s => !s.IsHandled && s.HandleType == WorkStepHandleType.Processing).ToList();
            //returnSteps.AddRange(processingList);

            return workSteps;
        }
    }
}